package com.ddd.config;

import com.ddd.core.constants.WebConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.Servlet;

/**
 * actuator 安全配置
 * 控制 actuator 的访问限制
 * 不对 spring-security 存在是否判断,如果没有依赖,直接报错
 */
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@AutoConfigureAfter(SecurityAutoConfiguration.class)
public class ActuatorSecurityAutoConfiguration {


    @Configuration
    @EnableWebSecurity
    @EnableConfigurationProperties(WebEndpointProperties.class)
    public static class ActuatorSecurityConfig {

        @Autowired
        private WebEndpointProperties webEndpointProperties;

        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public SecurityFilterChain securityAutoConfiguration(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers(webEndpointProperties.getBasePath() + "/**").authenticated()
                    .antMatchers(WebConstants.SWAGGER_PATH_PATTERNS).authenticated()
                    .antMatchers(WebConstants.EXCLUDE_PATH_PATTERNS).permitAll()
                    .anyRequest().permitAll()
                    .and().httpBasic()
            // 如果不配置 formLogin,不会重定向到登录页,因为不需要登录页面
            // spring-boot-admin 使用 httpbasic 验证
            // .and().formLogin()
            ;
            // 禁用 csrf
            http.csrf().disable();

            // https://docs.spring.io/spring-security/site/docs/5.0.5.RELEASE/reference/html/headers.html
            // 禁用 Strict-Transport-Security 响应头,该响应头在 nginx 中配置
            // 禁用安全请求头,在 nginx 中配置
            http.headers().defaultsDisabled().cacheControl();
            // https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referrer-Policy
            // 配置 referrer 头策略
            // 同源请求发送 referrer,其他仅发送 host,在 nginx 端配置
            // http.headers().referrerPolicy(ReferrerPolicy.ORIGIN_WHEN_CROSS_ORIGIN);
            // 禁用记住我
            http.rememberMe().disable();
            return http.build();
        }

    }
}
